package io.cici.cc.mybatis.lite.builder;

import io.cici.cc.mybatis.lite.executor.keygen.KeyGenerator;
import io.cici.cc.mybatis.lite.mapping.*;
import io.cici.cc.mybatis.lite.session.Configuration;
import io.cici.cc.mybatis.lite.type.TypeHandler;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;

@Setter
@Getter
public class MapperBuilder extends Builder {

    private final String resource;
    private String namespace;

    public MapperBuilder(Configuration configuration, String resource) {
        super(configuration);

        this.resource = resource;
    }


    public void setNamespace(@NonNull String namespace) {
        this.namespace = namespace;
    }


    public ParameterMappings addParameterMappings(String id, Class<?> parameterClass,
                                                  List<ParameterMapping> parameterMappingList) {

        ParameterMappings parameterMappings = new ParameterMappings.Builder(id, parameterClass, parameterMappingList).build();
        configuration.addParameterMappings(parameterMappings);
        return parameterMappings;
    }

    public ParameterMapping buildParameterMapping(Class<?> parameterType, String property, String type, TypeHandler typeHandler) {
        return new ParameterMapping.Builder(configuration, property, parameterType, type, typeHandler).build();
    }

    public ResultMappings addResultMap(String id, Class<?> type, List<ResultMapping> resultMappingList) {
        ResultMappings resultMappings = new ResultMappings.Builder(configuration, id, type, resultMappingList).build();
        configuration.addResultMap(resultMappings);
        return resultMappings;
    }

    public MappedStatement addMappedStatement(String id, SqlSource sqlSource, SqlCommandType sqlCommandType,
                                              String parameterMap, Class<?> parameterType, String resultMap,
                                              Class<?> resultType, KeyGenerator keyGenerator,
                                              String keyProperty, String keyColumn) {


        MappedStatement.Builder builder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
                .resource(resource).keyGenerator(keyGenerator).keyProperty(keyProperty)
                .keyColumn(keyColumn)
                .resultMaps(getStatementResultMappings(resultMap, resultType, id));

        ParameterMappings parameterMappings = getStatementParameterMap(parameterMap, parameterType, id);
        if (parameterMappings != null) {
            builder.parameterMap(parameterMappings);
        }

        MappedStatement mappedStatement = builder.build();
        configuration.addMappedStatement(mappedStatement);
        return mappedStatement;
    }


    private ParameterMappings getStatementParameterMap(String parameterMapName, Class<?> parameterTypeClass, String statementId) {

        ParameterMappings parameterMap = null;
        if (parameterMapName != null) {
            try {
                parameterMap = configuration.getParameterMap(parameterMapName);
            } catch (IllegalArgumentException e) {
                throw new IllegalArgumentException("Could not find parameter map " + parameterMapName, e);
            }
        } else if (parameterTypeClass != null) {
            List<ParameterMapping> parameterMappingList = new ArrayList<>();
            parameterMap = new ParameterMappings.Builder(statementId + "-Inline", parameterTypeClass, parameterMappingList)
                    .build();
        }
        return parameterMap;
    }

    private ResultMappings getStatementResultMappings(String resultMap, Class<?> resultType, String statementId) {


        if (resultMap != null) {
            return configuration.getResultMap(resultMap.trim());
        } else if (resultType != null) {
            ResultMappings resultMappings = new ResultMappings.Builder(configuration, statementId + "-Inline", resultType, new ArrayList<>()).build();
            return resultMappings;
        } else {
            return null;
        }

    }

    public ResultMapping buildResultMapping(String property, String column, String type, TypeHandler typeHandler) {
        return new ResultMapping.Builder(configuration, property, column, type, typeHandler).build();
    }


}
